/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = fix_core.c                                                    */
/*  NOTE      = DRDA协议解析                                                  */
/*  DATE      = 2015/03/18 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "fix_core.h"
#include "fix_comm.h"
#include "fix_request.h"
#include "fix_response.h"
#include "config.h"

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  初始化私有FIX session
*  ARGS     :  p_st_session(FIX私有session)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_session必须不为NULL
*******************************************************************************/
static int __fix_init_private(L7_session *p_st_session)
{
    L7_fragment_fix *p_st_fragment = NULL;               /* 分片包相关数据 */
    L7session_fix  *p_st_fix_conn = NULL;                /* 链接信息 */
    L7session_fix_private *p_st_private_session = NULL;  /* FIX私有session */

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_fix_private *)frmalloc(sizeof(L7session_fix_private));
    if (p_st_private_session == NULL)
    {
        goto error;
    }
    memset(p_st_private_session, 0x00, sizeof(L7session_fix_private));

    /* 申请链路信息结构内存 */
    p_st_fix_conn = (L7session_fix  *)frmalloc(sizeof(L7session_fix));
    if (p_st_fix_conn == NULL)
    {
        goto error;
    }
    memset(p_st_fix_conn, 0x00, sizeof(L7session_fix));

    /* 申请分片包信息结构内存 */
    p_st_fragment = (L7_fragment_fix *)frmalloc(sizeof(L7_fragment_fix));
    if (p_st_fragment == NULL)
    {
        goto error;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_fix));

    /* 设置初始化结构 */
    p_st_private_session->p_st_sess = p_st_fix_conn;
    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_session->p_session_private = p_st_private_session;
    return FR_SUCC;

error:
    fix_free((char **)(&p_st_private_session));
    fix_free((char **)(&p_st_fix_conn));
    fix_free((char **)(&p_st_fragment));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  初始化私有FIX session
*  ARGS     :  p_st_private(私有session数据)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_private必须不是NULL
*******************************************************************************/
static void __fix_destroy_curr_info(L7session_fix_private *p_st_private)
{
    if (p_st_private->p_st_req)
    {
        fix_destroy_request(&p_st_private->p_st_req);
    }
    if (p_st_private->p_st_resp)
    {
        fix_destroy_response(&p_st_private->p_st_resp);
    }
    fix_init_fragment(p_st_private->p_st_fragment);

    return;
}

/*******************************************************************************
*  FUNC     :  取得完整的packet包
*  ARGS     :  p_st_conn(connection信息)
*           :  p_st_packet(数据包信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
static int __fix_set_analysis_data(Conntrack *p_st_conn
                                  , Apm_packet *p_st_packet
                                  , L7session_fix_private *p_st_private)
{
    int i_ret = FR_SUCC;
    int i_req_resp = 0;
    unsigned ui_total_size = 0;
    unsigned int ui_hd_len = 0;
    unsigned int ui_bd_len = 0;
    unsigned int ui_len = p_st_packet->ui_payload_len;
    char *p_data = p_st_packet->p_payload;
    char *p_version = NULL;
    char *p_msg_type = NULL;
    char *p_input_msg = NULL;
    L7_fragment_fix *p_st_fragment = p_st_private->p_st_fragment;

    if (ui_len == 0)
    {
        return APM_L7_ANALYZE_TODO;
    }

    /* 取得方向 */
    i_req_resp = frcap_get_cs_direction(p_st_conn, p_st_packet->src_ip
                                       , p_st_packet->src_port);
    if (p_st_fragment->p_input_msg == NULL)
    {
        i_ret = fix_parse_header(p_data, ui_len, &ui_hd_len, &ui_bd_len
                                , &p_version, &p_msg_type);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        fix_free(&p_version);
        /* 长度不正 */
        if (ui_len > ui_hd_len + ui_bd_len + FIX_SHO_LEN)
        {
            fix_free(&p_msg_type);
            return APM_L7_ANALYZE_FAIL;
        }
        /* 一个分片包 */
        else if (ui_len == ui_hd_len + ui_bd_len + FIX_SHO_LEN)
        {
            p_st_fragment->i_req_resp = i_req_resp;
            p_st_fragment->ui_hd_len = ui_hd_len;
            p_st_fragment->ui_bd_len = ui_bd_len;
            p_st_fragment->ui_input_size = ui_len;
            p_st_fragment->i_new_flg = FR_NO;
            p_st_fragment->p_input_msg = p_data;
            p_st_fragment->p_msg_type = p_msg_type;
            p_st_fragment->st_start_timestamp = p_st_packet->st_timestamp;
            p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;
            return APM_L7_ANALYZE_SUCC;
        }
        /* 还有后续分片包 */
        else
        {
            p_input_msg = (char *)frmalloc(ui_len + 1);
            if (p_input_msg == NULL)
            {
                fix_free(&p_msg_type);
                return APM_L7_ANALYZE_FAIL;
            }
            memcpy(p_input_msg, p_data, ui_len);
            p_st_fragment->i_req_resp = i_req_resp;
            p_st_fragment->ui_hd_len = ui_hd_len;
            p_st_fragment->ui_bd_len = ui_bd_len;
            p_st_fragment->i_new_flg = FR_YES;
            p_st_fragment->ui_input_size = ui_len;
            p_st_fragment->p_input_msg = p_input_msg;
            p_st_fragment->p_msg_type = p_msg_type;
            p_st_fragment->st_start_timestamp = p_st_packet->st_timestamp;
            return APM_L7_ANALYZE_TODO;
        }
    }
    else
    {
        /* 前后两次方向不一致, 消除上次信息 */
        if (p_st_fragment->i_req_resp != i_req_resp)
        {
            fix_init_fragment(p_st_fragment);
            i_ret = __fix_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
            return i_ret;
        }
        else
        {
            ui_total_size = p_st_fragment->ui_hd_len + p_st_fragment->ui_bd_len + FIX_SHO_LEN;
            if (ui_len + p_st_fragment->ui_input_size > ui_total_size)
            {
                fix_init_fragment(p_st_fragment);
                i_ret = __fix_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
                return i_ret;
            }
            else if (ui_len + p_st_fragment->ui_input_size == ui_total_size)
            {
                memcpy(p_st_fragment->p_input_msg + p_st_fragment->ui_input_size
                       , p_data, ui_len);
                p_st_fragment->ui_input_size += ui_len;
                p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;
                return APM_L7_ANALYZE_SUCC;
            }
            else
            {
                memcpy(p_st_fragment->p_input_msg + p_st_fragment->ui_input_size
                       , p_data, ui_len);
                p_st_fragment->ui_input_size += ui_len;
                return APM_L7_ANALYZE_TODO;
            }
        }
    }
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是DRDA协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int fix_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = FR_SUCC;
    unsigned int ui_hd_len = 0;
    unsigned int ui_bd_len = 0;
    unsigned int ui_len = 0;
    char *p_data = NULL;
    char *p_version = NULL;
    char *p_msg_type = NULL;

    //入力参数检查
    if(p_st_packet == NULL || p_st_conn== NULL
       || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0)
        return APM_L7_IS_NO;

    ui_len = p_st_packet->ui_payload_len;         /* packet数据长度 */
    p_data = p_st_packet->p_payload;              /* packet数据内容 */

    i_ret = fix_parse_header(p_data, ui_len, &ui_hd_len, &ui_bd_len
                             , &p_version, &p_msg_type);
    fix_free(&p_version);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }
    /* 长度不正 */
    if (ui_len != ui_hd_len + ui_bd_len + FIX_SHO_LEN)
    {
        goto error;
    }

    /* 设置方向 */
    i_ret = FR_SUCC;
    if(frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        if (strcmp(p_msg_type, FIX_MSG_TP_LOGON) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_HEARTBEAT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_TEST_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_RESEND_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_SEQUENCE_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_LOGOUT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_NEW_ORDER_SINGLE) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_CANCEL_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_CANCEL_REPLACE_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_MASS_STATUS_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_MASS_CANCEL_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_MASS_QUOTE) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_QUOTE_CANCEL) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_SECURITY_DEFINITION_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_SECURITY_LIST_REQ) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_UNKNOW_TRADE) == 0)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip
                                    , p_st_packet->dst_port);
        }
        else if (strcmp(p_msg_type, FIX_MSG_TP_REJECT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_MASS_CANCEL_REPORT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_QUOTE_ACKNOWLEDGMENT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_EXECUTION_REPORT) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_SECURITY_DEFINITION) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_SECURITY_LIST) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_NEWS_MESSAGE) == 0
            || strcmp(p_msg_type, FIX_MSG_TP_ORDER_CANCEL_REJECT) == 0)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip
                                     , p_st_packet->src_port);
        }
        else
        {
            i_ret = FR_FAIL;
        }
    }

    if (i_ret != FR_SUCC)
    {
        goto error;
    }
    fix_free(&p_msg_type);
    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    return APM_L7_IS_YES;

error:
    fix_free(&p_msg_type);
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  FIX的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int fix_analysis(Conntrack *p_st_conn
                , Apm_packet *p_st_packet
                , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    L7_session *p_st_session = NULL;              /* L7session */
    L7session_fix_private *p_st_private = NULL;   /* FIX的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 如果入力p_st_packet是FIN包, 说明本次FIX的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,
    * 说明新的FIX的connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        /* 销毁所有相关本次FIX的connection的数据 */
        fix_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        /* 初始化FIX的私有数据 */
        i_ret = __fix_init_private(p_st_session);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_fix_private *)p_st_session->p_session_private;
    /* 设置解析数据 */
    i_ret = __fix_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
    if (i_ret == APM_L7_ANALYZE_TODO)
    {
        frdbg("need more data\n");
        return APM_L7_ANALYZE_TODO;
    }
    else if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frdbg("call __fix_set_analysis_data failed\n");
        __fix_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 解析packet */
    switch (p_st_private->p_st_fragment->i_req_resp)
    {
        case FR_CLIENT_IP_PORT: /* 解析request */
            i_ret = fix_parse_request(p_st_conn, p_st_private, p_st_hash_report);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse request failed\n");
                __fix_destroy_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }
            fix_init_fragment(p_st_private->p_st_fragment);
            break;

        case FR_SRV_IP_PORT: /* 解析response */
            i_ret = fix_parse_response(p_st_conn, p_st_private, p_st_hash_report);
            __fix_destroy_curr_info(p_st_private);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse response failed\n");
                return APM_L7_ANALYZE_FAIL;
            }
            break;

        default: /* 类型未知 */
            i_ret = APM_L7_ANALYZE_FAIL;
            break;
    }

    /* 返回 */
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(FIX的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int fix_session_destroy(void *p_private_session)
{
    L7session_fix_private *p_st_private = (L7session_fix_private *)p_private_session;

    /* 判断session是否为空 */
    if (p_st_private == NULL)
    {
        return FR_SUCC;
    }

    /* 销毁session数据 */
    if (p_st_private->p_st_sess)
    {
        fix_destroy_session(&(p_st_private->p_st_sess));
    }

    /* 销毁request数据 */
    if (p_st_private->p_st_req)
    {
        fix_destroy_request(&(p_st_private->p_st_req));
    }

    /* 销毁response数据 */
    if (p_st_private->p_st_resp)
    {
        fix_destroy_response(&p_st_private->p_st_resp);
    }

    /* 销毁分片数据 */
    if (p_st_private->p_st_fragment)
    {
        fix_destroy_fragment(&p_st_private->p_st_fragment);
    }

    frfree(p_st_private);

    return FR_SUCC;
}
